package com.glink.manage.service.Impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glink.common.contants.BaseCodeConstants;
import com.glink.common.exception.GeneralSimpleException;
import com.glink.common.util.BaseCommonUtils;
import com.glink.manage.common.BeanKit;
import com.glink.manage.domain.MenuBean;
import com.glink.manage.domain.MenuFunctionUriBean;
import com.glink.manage.dto.menu.MenuFunctionPointsSaveRequestDTO;
import com.glink.manage.dto.menu.MenuFunctionPointsUpdateRequestDTO;
import com.glink.manage.dto.menu.MenuSaveRequestDTO;
import com.glink.manage.dto.menu.MenuUpdateRequestDTO;
import com.glink.manage.mapper.MenuMapper;
import com.glink.manage.service.MenuFunctionUriService;
import com.glink.manage.service.MenuService;
import com.glink.manage.service.RoleMenuRelaService;
import com.glink.manage.service.RoleService;
import com.glink.manage.vo.menu.*;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static java.util.Objects.nonNull;
@Slf4j
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuBean> implements MenuService {

    /**
     * 系统管理员角色
     */
    @Value("${user.default_role.system_admin:ADMIN}")
    private String systemAdminRole;
    
    @Autowired
    private MenuFunctionUriService menuFunctionUriService;    
    
    @Autowired
    @Lazy
    private RoleService roleService;
    
    
    @Autowired
    @Lazy
    private RoleMenuRelaService roleMenuRelaService;
    
    /**
     * 根据菜单ID获取菜单实体
     * @param id 菜单ID
     * @return 菜单实体
     */
    private MenuBean getMenuById(String id) {
        return lambdaQuery()
                .eq(MenuBean::getId, id)
                .one();
    }

    /**
     * 查询所有菜单，排除掉按钮
     * @return 菜单列表
     */
    @Override
    public List<MenuInfoVO> getMenuList() {
        List<MenuInfoVO> menuInfoVOList = Lists.newArrayList();
        List<MenuBean> menuBeanList = lambdaQuery()
                .ne(MenuBean::getType, BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)
                .orderByAsc(MenuBean::getPid)
                .orderByAsc(MenuBean::getIdx)
                .orderByAsc(MenuBean::getCreateTime)
                .orderByAsc(MenuBean::getId)
                .list();
        
        if(CollectionUtils.isNotEmpty(menuBeanList)){
            menuBeanList.forEach(menuBean -> {
                MenuInfoVO menuInfoVO = beanToVo(menuBean);
                Integer count = lambdaQuery()
                        .eq(MenuBean::getType, BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)
                        .eq(MenuBean::getPid, menuInfoVO.getMenuId())
                        .count();
                if(Objects.nonNull(count) && count > 0){
                    menuInfoVO.setIsChildren(BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode01);
                }else{
                    menuInfoVO.setIsChildren(BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode02);
                }
                menuInfoVOList.add(menuInfoVO);
                
            });
        }
        return menuInfoVOList;
    }
 
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int deleteResourceById(String id) throws GeneralSimpleException {

        List<MenuBean> menuBeanList = this.lambdaQuery().eq(MenuBean::getId, id).list();
        if(CollectionUtils.isNotEmpty(menuBeanList)){
            MenuBean menuBean = menuBeanList.get(0);
            // 不是按钮，则根据自己的类型查询是否存在下级菜单
            if(!StringUtils.equals(menuBean.getType(), BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)){
                List<MenuBean> childMenuList = this.lambdaQuery()
                        .eq(MenuBean::getPid, id)
                        .eq(MenuBean::getType, menuBean.getType())
                        .list();
                if(CollectionUtils.isNotEmpty(childMenuList)){
                    //400017=菜单删除失败：该菜单[{0}]存在子菜单，无法删除
                   throw new GeneralSimpleException("400017", menuBean.getName());
                }
            }else{
                // 按钮需要删除对应的地址信息
                boolean status = menuFunctionUriService.deleteByMenuId(id);
                if(!status){
                    throw new GeneralSimpleException("400027", menuBean.getName());
                }
            }
            // 是按钮，则删除自己
            int deleteNum = baseMapper.delete(
                    Wrappers.lambdaUpdate(MenuBean.class)
                            .eq(MenuBean::getId, id));
            if(deleteNum == 0){
                throw new GeneralSimpleException("400027", menuBean.getName());
            }
            
            roleMenuRelaService.deleteByMenuId(id);
            
            return deleteNum;
        }else{
            throw new GeneralSimpleException("400016", id);
        }
    }

    /**
     * 根据类型列表查询菜单信息 
     * @param typeList 类别列表
     * @return 菜单信息
     */
    @Override
    public List<MenuBranchVO> findAllMenuListByType(List<String> typeList) {
        List<MenuBranchVO> menuList = baseMapper.findAllMenuList(typeList);
        if (CollectionUtils.isEmpty(menuList)){
            return null;
        }
        menuList.parallelStream().forEach(x->{
            if(CollectionUtils.isNotEmpty(x.getChildren())){
                x.getChildren().parallelStream().forEach(child -> {
                    if (StringUtils.equals(child.getType(), BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)){
                        // 按钮，返回菜单地址
                        child.setUriList(menuFunctionUriService.findUriByMenuId(child.getMenuId()));
                    }
                });
            }
        });
        return menuList;
    }

    /**
     * 根据菜单ID获取菜单信息
     * @param list 菜单ID数组
     * @return 菜单信息
     */
    @Override
    public List<MenuSimpleInfoVO> getMenuList(List<String> list) {
        List<MenuSimpleInfoVO> simpleInfoVOList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(list)){
            List<MenuBean> menuBeanList = this.lambdaQuery().in(MenuBean::getId, list).list();
            if (CollectionUtils.isEmpty(menuBeanList)){
                return simpleInfoVOList;
            }
            menuBeanList.forEach(menuBean->{
                MenuSimpleInfoVO menuSimpleInfoVO = new MenuSimpleInfoVO();
                BeanKit.copyProperties(menuBean, menuSimpleInfoVO);
                menuSimpleInfoVO.setMenuId(menuBean.getId());
                menuSimpleInfoVO.setMenuName(menuBean.getName());
                simpleInfoVOList.add(menuSimpleInfoVO);
            });
        }
       
        return simpleInfoVOList;
    }
    
    @Override
    public List<MenuFunctionInfoVO> getButtonList(String pid) {
        List<MenuFunctionInfoVO> menuInfoVOList = Lists.newArrayList();
        List<MenuBean> menuBeanList = this.lambdaQuery()
                .eq(MenuBean::getType, BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)
                .eq(MenuBean::getPid, pid)
                .orderByDesc(MenuBean::getCreateTime)
                .orderByAsc(MenuBean::getId)
                .list();
        if(CollectionUtils.isNotEmpty(menuBeanList)){
            menuBeanList.forEach(menuBean -> {
                menuInfoVOList.add(beanToFunctionVo(menuBean));
            });
        }
        return menuInfoVOList;
    }

    /**
     * 新增菜单
     * @param saveRequestVO 菜单信息
     * @return 菜单信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public MenuInfoVO insertMenu(MenuSaveRequestDTO saveRequestVO) throws GeneralSimpleException {

        String key = saveRequestVO.getKey();
        // 校验key是否重复
        if(StringUtils.isNotEmpty(key)){
            List<MenuBean> oneList = this.lambdaQuery().eq(MenuBean::getKey, key)
                    .list();
            if(CollectionUtils.isNotEmpty(oneList)){
                throw new GeneralSimpleException("400026", key);
            }
        }
        
        MenuBean menuBean = new MenuBean();
        BeanUtils.copyProperties(saveRequestVO, menuBean);
        menuBean.setName(saveRequestVO.getMenuName());
        menuBean.setUri(saveRequestVO.getUri());
        menuBean.setType(StringUtils.isNotEmpty(menuBean.getType()) ? menuBean.getType() : BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType01);
        String id = BaseCommonUtils.generateUUID();
        menuBean.setId(id);
        MenuInfoVO menuInfoVO = null;
        try {
            menuInfoVO = beanToVo(baseMapper.insert(menuBean) > 0 ? menuBean : null);    
        }catch (Exception e){
            throw new GeneralSimpleException("200001");
        }
        
        // 菜单添加成果，给系统管理员角色添加菜单权限
//        if(StringUtils.isNotEmpty(menuInfoVO.getMenuId())){
//            List<String> roleIdList = Lists.newArrayList(systemAdminRole);
//            roleMenuRelaService.saveRelaByRoleIdAndMenuId(roleIdList, menuBean.getId());   
//        }
        
        return menuInfoVO;
    }

    /**
     * 更新菜单
     * @param saveRequestVO 菜单信息
     * @return 菜单信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public MenuInfoVO updateMenu(MenuUpdateRequestDTO saveRequestVO) throws GeneralSimpleException {

        final Date now = new Date();
        final String menuId = saveRequestVO.getMenuId();
        if (StringUtils.isNotEmpty(menuId)) {
            MenuBean byId = getMenuById(menuId);
            if (nonNull(byId)) {

                String key = saveRequestVO.getKey();
                // 校验key是否重复
                if(StringUtils.isNotEmpty(key)){
                    MenuBean one = this.lambdaQuery()
                            .eq(MenuBean::getKey, key)
                            .ne(MenuBean::getId, menuId)
                            .one();
                    if(Objects.nonNull(one)){
                        throw new GeneralSimpleException("400026", key);
                    }
                }
                
                BeanUtils.copyProperties(saveRequestVO, byId, BaseCommonUtils.getNullPropertyNames(saveRequestVO));
                byId.setName(saveRequestVO.getMenuName());
                byId.setId(saveRequestVO.getMenuId());
                byId.setUri(saveRequestVO.getUri());
                byId.setUpdateTime(now);
                int update = 0;
                try {
                    update = baseMapper.update(byId,
                            Wrappers.lambdaUpdate(MenuBean.class)
                                    .eq(MenuBean::getId, menuId));
                }catch (Exception e){
                    throw new GeneralSimpleException("200001");
                }
                MenuBean menuBean = update > 0 ? byId : null;
                return beanToVo(menuBean);
            }else{
                throw new GeneralSimpleException("400016", menuId);
            }
        }
        return null;
    }

    public static void main(String[] args) {
        List<String> test = Lists.newArrayList();

        test.add("111111");
        String collect = String.join(",", test);
        System.out.println(collect);

        List<String> list = Arrays.asList(collect.split(","));
        System.out.println(list);
    }
    
    /**
     * 新增功能点
     * @param dto 功能点信息
     * @return 功能点信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public MenuFunctionInfoVO insertFunctionPoints(MenuFunctionPointsSaveRequestDTO dto) throws GeneralSimpleException {

        String key = dto.getKey();
        // 校验key是否重复
        if(StringUtils.isNotEmpty(key)){
            List<MenuBean> oneList = this.lambdaQuery()
                    .eq(MenuBean::getKey, key)
                    .eq(MenuBean::getPid, dto.getPid())
                    .list();
            if(CollectionUtils.isNotEmpty(oneList)){
                throw new GeneralSimpleException("400026", key);
            }
        }
        
        MenuBean menuBean = new MenuBean();
        BeanUtils.copyProperties(dto, menuBean);

        menuBean.setName(dto.getMenuName());
        String id = BaseCommonUtils.generateUUID();
        menuBean.setId(id);
        menuBean.setType(BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02);
        menuBean.setUri(null);
        int insert = baseMapper.insert(menuBean);
        MenuFunctionInfoVO menuInfoVO = new MenuFunctionInfoVO();
        if(insert > 0){
            List<MenuFunctionUriBean> uriBeanList = uriToMenuFunctionUriBean(menuBean.getId(), dto.getUriList());
            if(CollectionUtils.isNotEmpty(uriBeanList)){
                menuFunctionUriService.saveBatch(uriBeanList);
            }

            menuInfoVO = beanToFunctionVo(menuBean);

            // 菜单添加成果，给系统管理员角色添加菜单权限
            List<String> roleIdList = Lists.newArrayList(systemAdminRole);
            roleMenuRelaService.saveRelaByRoleIdAndMenuId(roleIdList, menuBean.getId());
        }
        
        return menuInfoVO;
    }

    /**
     * 更新功能点
     * @param dto 功能点信息
     * @return 功能点信息
     */
    @Override
    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public MenuFunctionInfoVO updateFunctionPoints(MenuFunctionPointsUpdateRequestDTO dto) throws GeneralSimpleException {

        final Date now = new Date();
        final String menuId = dto.getMenuId();
        if (StringUtils.isNotEmpty(menuId)) {
            MenuBean menuBean = getMenuById(menuId);
            if (nonNull(menuBean)) {

                String key = dto.getKey();
                // 校验key是否重复
                if(StringUtils.isNotEmpty(key)){
                    List<MenuBean> oneList = this.lambdaQuery()
                            .eq(MenuBean::getKey, key)
                            .eq(MenuBean::getPid, dto.getPid())
                            .ne(MenuBean::getId, menuId)
                            .list();
                    if(CollectionUtils.isNotEmpty(oneList)){
                        throw new GeneralSimpleException("400026", key);
                    }
                }
                
                BeanUtils.copyProperties(dto, menuBean, BaseCommonUtils.getNullPropertyNames(dto));
                menuBean.setName(dto.getMenuName());
                menuBean.setUpdateTime(now);
                menuBean.setId(menuId);
                menuBean.setUri(null);
                final int update = baseMapper.update(menuBean,
                        Wrappers.lambdaUpdate(MenuBean.class)
                                .eq(MenuBean::getId, menuId)
                );

                MenuFunctionInfoVO menuInfoVO = new MenuFunctionInfoVO();
                if(update > 0){
                    List<MenuFunctionUriBean> uriBeanList = uriToMenuFunctionUriBean(menuBean.getId(), dto.getUriList());
                    if(CollectionUtils.isNotEmpty(uriBeanList)){
                        menuFunctionUriService.deleteByMenuId(menuBean.getId());
                        menuFunctionUriService.saveBatch(uriBeanList);
                    }
                    
                    menuInfoVO = beanToFunctionVo(menuBean);
                }
                
                return menuInfoVO;
            }else{
                throw new GeneralSimpleException("400016", menuId);
            }
        }

        return null;
    }

    /**
     * uri转功能点地址对象
     * @param menuId 菜单ID
     * @param uriList 地址列表
     * @return 功能点地址对象
     */
    private List<MenuFunctionUriBean> uriToMenuFunctionUriBean(String menuId, List<String> uriList){
        List<MenuFunctionUriBean> uriBeanList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(uriList)){
            uriList.forEach(uri -> {
                MenuFunctionUriBean menuFunctionUriBean = new MenuFunctionUriBean();
                menuFunctionUriBean.setId(BaseCommonUtils.generateUUID());
                menuFunctionUriBean.setMenuId(menuId);
                menuFunctionUriBean.setUri(uri);
                uriBeanList.add(menuFunctionUriBean);
            });
        }
        return uriBeanList;
    }
    
    /**
     * 根据菜单ID获取菜单信息
     *
     * @param menuId 菜单ID
     * @return 菜单信息
     */
    @Override
    public MenuInfoVO getMenuInfoById(String menuId) {

        MenuInfoVO menuInfoVO = new MenuInfoVO();
        MenuBean menuBean = getMenuById(menuId);
        if(Objects.nonNull(menuBean)){
            menuInfoVO = beanToVo(menuBean);
            Integer count = lambdaQuery()
                    .eq(MenuBean::getType, BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)
                    .eq(MenuBean::getPid, menuInfoVO.getMenuId())
                    .count();
            if(Objects.nonNull(count) && count > 0){
                menuInfoVO.setIsChildren(BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode01);
            }else{
                menuInfoVO.setIsChildren(BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode02);
            }
        }
        return menuInfoVO;
    }

    /**
     * 根据菜单ID查询菜单信息
     *
     * @param menuIdList 菜单ID
     * @return 菜单信息
     */
    @Override
    public List<MenuBranchVO> findAllMenuListById(List<String> menuIdList) {
        List<MenuBranchVO> menuBranchVOList = Lists.newArrayList();
        List<MenuBean> menuBeanList = this.lambdaQuery().in(MenuBean::getId, menuIdList)
                .ne(MenuBean::getType, BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)
                .eq(MenuBean::getIsEnable, BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode01)
                .list();
        if(CollectionUtils.isNotEmpty(menuBeanList)){
            menuBeanList.forEach(menuBean -> {
                MenuBranchVO menuBranchVO = new MenuBranchVO();
                BeanKit.copyProperties(menuBean, menuBranchVO);
                menuBranchVO.setMenuId(menuBean.getId());
                menuBranchVOList.add(menuBranchVO);
                // 非按钮的菜单，获取所属的按钮
                if(!StringUtils.equals(menuBean.getType(), BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)){

                    List<MenuBean> menuButBeanList = this.lambdaQuery()
                            .eq(MenuBean::getType, BaseCodeConstants.CodeType_MenuResourceType.KEY_MenuResourceType02)
                            .in(MenuBean::getId, menuIdList)
                            .eq(MenuBean::getPid, menuBean.getId())
                            .list();
                    
                    if(CollectionUtils.isNotEmpty(menuButBeanList)){
                        List<MenuLeafVO> children = Lists.newArrayList();
                        menuButBeanList.forEach(menuButBean -> {
                            MenuLeafVO menuLeafVO = new MenuLeafVO(); 
                            BeanKit.copyProperties(menuButBean, menuLeafVO);
                            menuLeafVO.setMenuId(menuButBean.getId());
                            menuLeafVO.setUriList(menuFunctionUriService.findUriByMenuId(menuButBean.getId()));
                            children.add(menuLeafVO);
                        });
                        menuBranchVO.setChildren(children);
                    }
                }
            });
        }
        return menuBranchVOList;
    }

    /**
     * 实体转VO
     * @param menuBean 菜单
     * @return 菜单信息
     */
    private MenuInfoVO beanToVo(MenuBean menuBean){
        MenuInfoVO menuInfoVO = new MenuInfoVO();
        if(Objects.nonNull(menuBean)){
            BeanUtils.copyProperties(menuBean, menuInfoVO);
            menuInfoVO.setIsEnable(StringUtils.isNotEmpty(menuInfoVO.getIsEnable()) ? menuInfoVO.getIsEnable() : BaseCodeConstants.CodeType_WhetherCode.KEY_WhetherCode01);
            menuInfoVO.setMenuId(menuBean.getId());
            menuInfoVO.setMenuName(menuBean.getName());
        }
        return menuInfoVO;
    }

    /**
     * 实体转功能点VO
     * @param menuBean 菜单
     * @return 菜单信息
     */
    private MenuFunctionInfoVO beanToFunctionVo(MenuBean menuBean){
        MenuFunctionInfoVO menuInfoVO = new MenuFunctionInfoVO();
        if(Objects.nonNull(menuBean)){
            BeanUtils.copyProperties(menuBean, menuInfoVO);
            menuInfoVO.setMenuId(menuBean.getId());
            menuInfoVO.setMenuName(menuBean.getName());

            List<String> uriList = menuFunctionUriService.findUriByMenuId(menuBean.getId());
            if(CollectionUtils.isNotEmpty(uriList)){
                menuInfoVO.setUriList(uriList);
            }
        }
        return menuInfoVO;
    }

    /**
     * 实体转VO
     * @param menuBean 菜单
     * @return 菜单信息
     */
    private MenuSimpleInfoVO beanToSimpleVo(MenuBean menuBean){
        MenuSimpleInfoVO menuInfoVO = new MenuSimpleInfoVO();
        if(Objects.nonNull(menuBean)){
            BeanUtils.copyProperties(menuBean, menuInfoVO);
            menuInfoVO.setIsEnable(StringUtils.isNotEmpty(menuInfoVO.getIsEnable()) ? menuInfoVO.getIsEnable() : "0");
            menuInfoVO.setMenuId(menuBean.getId());
            menuInfoVO.setMenuName(menuBean.getName());
        }
        return menuInfoVO;
    }
}
